package fr.lip6.meta.ple.generation.aspectj;

import java.util.HashMap;

import org.eclipse.emf.common.util.EList;
import org.eclipse.gmt.modisco.java.BodyDeclaration;
import org.eclipse.gmt.modisco.java.ClassDeclaration;
import org.eclipse.gmt.modisco.java.ConstructorDeclaration;
import org.eclipse.gmt.modisco.java.MethodDeclaration;
import org.eclipse.gmt.modisco.java.SingleVariableDeclaration;
import org.eclipse.gmt.modisco.java.Statement;
import org.eclipse.gmt.modisco.java.TypeAccess;
import org.eclipse.gmt.modisco.java.emf.impl.ConstructorDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.FieldDeclarationImpl;

public class ReadXmiAJ extends ReadXmi {
	
	public String getClassDeclarationAndBodyText(	ClassDeclaration classDecl,
															String featureName,
															boolean refine	) {
		StringBuilder res = new StringBuilder();
		EList<BodyDeclaration> bodyDecls;
		boolean	fieldPrev = false,
				consPrev = false,
				methodPrev = false;

		res.append(getClassDeclarationText(classDecl, featureName, refine));
		res.append(" {\n");
		
		bodyDecls = classDecl.getBodyDeclarations();

		//read body declaration 
		for(BodyDeclaration bobyDecl : bodyDecls) {
			if (bobyDecl instanceof FieldDeclarationImpl) {
				FieldDeclarationImpl fieldDecl = (FieldDeclarationImpl) bobyDecl;
				
				if (consPrev || methodPrev)
			    	res.append("\n");
				
				res.append("\t");
			    res.append(getFieldDeclarationText(fieldDecl));
			    
			    fieldPrev = true;
			    consPrev = false;
			    methodPrev = false;
			}
			
			if (bobyDecl instanceof ConstructorDeclaration) {
				ConstructorDeclarationImpl consDecl = (ConstructorDeclarationImpl) bobyDecl;
				
				if (fieldPrev || methodPrev)
			    	res.append("\n\n");
				else
					res.append("\n");

				res.append("\t");
				res.append(getConstructorDeclarationAndBodyText(consDecl));
			    
				consPrev = true;
			    fieldPrev = false;
			    methodPrev = false;
			}

			if (bobyDecl instanceof MethodDeclaration) {
				MethodDeclaration methodDecl = (MethodDeclaration) bobyDecl;
				
				if (fieldPrev || consPrev)
					res.append("\n\n");
				else
					res.append("\n");
				
				
				res.append("\t");
				res.append(getMethodDeclarationAndBodyText(methodDecl));
			    
				methodPrev = true;
			    fieldPrev = false;
			    consPrev = false;
			}
			
			res.append("\n");
		}

		res.append("\n}");

		return res.toString();
	}
	
	public static String getClassDeclarationText(ClassDeclaration clDecl, String featureName, boolean refine) {
		StringBuilder str = new StringBuilder();
		TypeAccess tp = clDecl.getSuperClass();

		// str.append("package "+c.getPackage().getName()+";\n");
		if(tp == null) {
			str.append(clDecl.getModifier().getVisibility() +" class "+clDecl.getName()+featureName); 
		} else {
			str.append(clDecl.getModifier().getVisibility() +" class "+clDecl.getName()+featureName +" extends "+tp.getType().getName());   
		}
		
		featureName = "";
		
		return str.toString();
	}
	
	static HashMap<String, String> getFieldDeclarationTextList(FieldDeclarationImpl fd) {
		HashMap<String, String> fieldDecl = new HashMap<String, String>();

		fieldDecl.put("visibility", fd.getModifier().getVisibility().getName());
		fieldDecl.put("type", fd.getType().getType().getName());
		fieldDecl.put("name", fd.getFragments().get(0).getName());

		return fieldDecl;
	}

	HashMap<String, String> getMethodDeclarationAndBodyTextList(MethodDeclaration methodDecl) {
		HashMap<String, String> mdbText;
		StringBuilder res = new StringBuilder();
		String returnType = methodDecl.getReturnType().getType().getName();
		EList<Statement> sts;
		org.eclipse.gmt.modisco.java.Block blck;

		mdbText = new HashMap<String, String>(getMethodDeclarationTextList(methodDecl));
		res.append(" {\n");

		blck = methodDecl.getBody();

		sts = blck.getStatements();

		for(Statement st : sts) {
			res.append(getStatement(st));
			res.append("\n");
		}
		
		if (returnType.equals("void")) {
			res.append("\t}");
		} else {
			res.append("\t}");
		}
		
		mdbText.put("body", res.toString());
		
		return mdbText;
	}
	
	static HashMap<String, String> getMethodDeclarationTextList(MethodDeclaration methodDecl) {
		HashMap<String, String> mdText = new HashMap<String, String>();
		String vis = methodDecl.getModifier().getVisibility().getName();
		String returnType = methodDecl.getReturnType().getType().getName();
		EList<SingleVariableDeclaration> parameters = methodDecl.getParameters();
		String parametersText = "";
		int i = 0; 
		
		mdText.put("visibility", vis);
		mdText.put("type", returnType);
		mdText.put("name", methodDecl.getName());

		if (parameters.size() != 0) {
			for(SingleVariableDeclaration var : parameters) {
				i++;
				if (i != parameters.size()) {
					parametersText += var.getType().getType().getName() +" "+var.getName()+", ";
				} else {
					parametersText += var.getType().getType().getName() +" "+var.getName();
				}
			}
		}
		
		mdText.put("parameters", parametersText);

		return mdText;
	}
	
	HashMap<String, String> getConstructorDeclarationAndBodyTextList(ConstructorDeclaration consDecl) {
		HashMap<String, String> mdbText;
		StringBuilder res = new StringBuilder();
		EList<Statement> sts;
		org.eclipse.gmt.modisco.java.Block blck;

		mdbText = new HashMap<String, String>(getConstructorDeclarationTextList(consDecl));
		res.append(" {\n");

		blck = consDecl.getBody();

		sts = blck.getStatements();

		for(Statement st : sts) {
			res.append(getStatement(st));
			res.append("\n");
		}
		
		res.append("\t}");
		
		mdbText.put("body", res.toString());
		
		return mdbText;
	}
	
	static HashMap<String, String> getConstructorDeclarationTextList(ConstructorDeclaration consDecl) {
		HashMap<String, String> mdText = new HashMap<String, String>();
		String vis = consDecl.getModifier().getVisibility().getName();
		EList<SingleVariableDeclaration> parameters = consDecl.getParameters();
		String parametersText = "";
		int i = 0;
		
		mdText.put("visibility", vis);
		mdText.put("name", consDecl.getName());

		if (parameters.size() != 0) {
			for(SingleVariableDeclaration var : parameters) {
				i++;
				if (i != parameters.size()) {
					parametersText += var.getType().getType().getName() +" "+var.getName()+", ";
				} else {
					parametersText += var.getType().getType().getName() +" "+var.getName();
				}
			}
		}
		
		mdText.put("parameters", parametersText);

		return mdText;
	}
}